package com.example.job.handler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.common.core.constants.CacheConstants;
import com.example.common.core.constants.Constants;
import com.example.common.redis.service.RedisService;
import com.example.job.domain.exam.Exam;
import com.example.job.domain.message.Message;
import com.example.job.domain.message.MessageText;
import com.example.job.domain.message.vo.MessageTextVO;
import com.example.job.domain.user.UserScore;
import com.example.job.mapper.exam.ExamMapper;
import com.example.job.mapper.message.MessageTextMapper;
import com.example.job.mapper.user.UserSubmitMapper;
import com.example.job.service.IMessageService;
import com.example.job.service.IMessageTextService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ExamXxlJob {

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IMessageService messageService;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private IMessageTextService messageTextService;

    //这里面配置的名称要和任务管理器中的一致的
    @XxlJob("examListOrganizeHandler")
    public void examListOrganizeHandler() {
        //统计哪些竞赛存入未完赛的列表中  哪些竞赛应该存入历史竞赛列表中  统计出来之后,再存入对应的缓存中 --> 刷新缓存
        log.info(" *** examListOrganizeHandler *** ");
        List<Exam> umFinishList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime, Exam::getEndTime)
                .gt(Exam::getEndTime, LocalDateTime.now())
                .eq(Exam::getStatus, Constants.TRUE)
                .orderByDesc(Exam::getCreateTime));
        System.out.println("umFinishList : " + umFinishList.toString());
        refreshCache(umFinishList,CacheConstants.EXAM_UNFINISHED_LIST);

        List<Exam> historyList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime, Exam::getEndTime)
                .le(Exam::getEndTime, LocalDateTime.now())
                .eq(Exam::getStatus, Constants.TRUE)
                .orderByDesc(Exam::getCreateTime));

        System.out.println("historyList : " + historyList.toString());
        refreshCache(historyList,CacheConstants.EXAM_HISTORY_LIST);
    }

    //统计竞赛排名生成消息
    @XxlJob("examResultHandler")
    public void examResultHandler() {
        //获取前一天结束的竞赛id
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime minusDateTime = now.minusDays(1);
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle)
                .eq(Exam::getStatus, Constants.TRUE)
                .ge(Exam::getEndTime, minusDateTime)
                .le(Exam::getEndTime, now));
        if (CollectionUtil.isEmpty(examList)) {
            return;
        }
        //使用set进行管理(避免重复)
        Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet());
        //获取排名统计
        List<UserScore> userScoreList = userSubmitMapper.selectUserScoreList(examIdSet);
        //根据竞赛id进行分组
        Map<Long,List<UserScore>> userScoerMap = userScoreList.stream().collect(Collectors.groupingBy(UserScore::getExamId));
        //消息发送 数据库 + redis
        createMessage(examList,userScoerMap);
    }

    //这里的缓存刷新逻辑直接去ExamCacheManager中进行copy
    //刷新缓存逻辑
    public void refreshCache(List<Exam> examList, String examListKey) {
        System.out.println("刷新redis捕获到的examList : " + examList.toString());
        if (CollectionUtil.isEmpty(examList)) {
            return;
        }

        Map<String, Exam> examMap = new HashMap<>();
        List<Long> examIdList = new ArrayList<>();
        for (Exam exam : examList) {
            examMap.put(getDetailKey(exam.getExamId()), exam);
            examIdList.add(exam.getExamId());
        }
        redisService.multiSet(examMap);  //刷新详情缓存
        redisService.deleteObject(examListKey);
        redisService.rightPushAll(examListKey, examIdList); //刷新列表缓存
    }

    //生成 + 发送消息
    private void createMessage(List<Exam> examIdSet, Map<Long, List<UserScore>> userScoerMap) {
        List<MessageText> messageTextList = new ArrayList<>();
        List<Message> messageList = new ArrayList<>();
        //数据库维护
        for (Exam exam : examIdSet) {
            Long examId = exam.getExamId();
            //当前进行排名数据
            List<UserScore> userScoreList = userScoerMap.get(examId);
            //当前竞赛总人数
            int totalUser = userScoreList.size();
            //userScoreList是根据总分进行排好序的
            int examRank = 1;
            for (UserScore userScore : userScoreList) {
                String messageTitle = exam.getTitle() + "--排名情况";
                String msgContent = "您所参与的竞赛: " + exam.getTitle() +
                        ", 本次参与竞赛一共" + totalUser + "人, 您排名第" + examRank + "名!!";
                //存储数据库
                MessageText messageText = new MessageText();
                messageText.setMessageTitle(messageTitle);
                messageText.setMessageContent(msgContent);
                messageText.setCreateBy(Constants.SYSTEM_USER_ID); //创建人为系统
                messageTextList.add(messageText);//先存储List,后续直接批量插入


                Message message = new Message();
                message.setSendId(Constants.SYSTEM_USER_ID);
                message.setCreateBy(Constants.SYSTEM_USER_ID);
                message.setRecId(userScore.getUserId());
                messageList.add(message);
                examRank++;
            }
        }
        messageTextService.batchInsert(messageTextList);
        //存储redis中的题目详情集合 + message中的textId赋值
        Map<String,MessageTextVO> messageTextVOMap = new HashMap<>();
        for (int i = 0; i < messageTextList.size(); i++) {
            MessageText messageText = messageTextList.get(i);
            //给messageId进行赋值 -- 创建是的顺序是一样的,可以通过i去进行下标获取
            Message message = messageList.get(i);
            message.setTextId(messageText.getTextId());

            //生成redis中存储信息
            MessageTextVO messageTextVO = new MessageTextVO();
            BeanUtil.copyProperties(messageText,messageTextVO);
            String msgDetailKey = getMsgDetailKey(messageText.getTextId());
            messageTextVOMap.put(msgDetailKey,messageTextVO);
        }

        messageService.batchInsert(messageList);
        //redis维护
        //根据用户id(接收人id)进行分组
        Map<Long,List<Message>> userMsgMap = messageList.stream().collect(Collectors.groupingBy(Message::getRecId));
        Iterator<Map.Entry<Long,List<Message>>> iterator = userMsgMap.entrySet().iterator();
        //维护用户消息缓存
        while(iterator.hasNext()){
            Map.Entry<Long,List<Message>> entry = iterator.next();
            Long userId = entry.getKey();
            String UserMsgListKey = getUserMsgListKey(userId);
            //message中只存储textId,不负责存储详情
            List<Long> userMsgTextIdList = entry.getValue().stream().map(Message::getTextId).toList();
            redisService.rightPushAll(UserMsgListKey, userMsgTextIdList);
        }
        //维护消息详情信息缓存
        redisService.multiSet(messageTextVOMap);
    }


    private String getDetailKey(Long examId) {
        return CacheConstants.EXAM_DETAIL + examId;
    }

    private String getUserMsgListKey(Long userId) {
        return CacheConstants.USER_EXAM_LIST + userId;
    }

    private String getMsgDetailKey(Long textId) {
        return CacheConstants.EXAM_DETAIL + textId;
    }
}
